﻿using System;
using System.Collections.Generic;
using System.Text;

namespace FySystem.IOTFlow
{
    public class ReadonlyFlow
    {
        private byte[] _arr = null;

        /// <summary>
        /// 是否为大端，由于大多数物联网协议都是大端，所以默认为true
        /// </summary>
        public bool IsBigEndian { get; set; } = true;

        /// <summary>
        /// 当前流位置
        /// </summary>
        public int Position { get; set; } = 0;

        /// <summary>
        /// 物联网专用高效只读流，用于读取设备上传的字节流数据，基于NumberConversion
        /// </summary>
        /// <param name="data"></param>
        /// <param name="isBigEndian"></param>
        public ReadonlyFlow(byte[] data, bool isBigEndian = true)
        {
            _arr = data;
            IsBigEndian = isBigEndian;
        }

        /// <summary>
        /// 物联网专用高效只读流，用于读取设备上传的字节流数据，基于NumberConversion
        /// </summary>
        /// <param name="data"></param>
        /// <param name="offset"></param>
        /// <param name="length"></param>
        /// <param name="isBigEndian"></param>
        public ReadonlyFlow(byte[] data, int offset, int length, bool isBigEndian = true)
        {
            try
            {
                _arr = data.AsSpan(offset, length).ToArray();
                IsBigEndian = isBigEndian;
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// 跳过指定字节数量
        /// </summary>
        /// <param name="length"></param>
        public void Skip(int length)
        {
            try
            {
                if (IsOverflow(length))
                    throw new Exception("ReadOnlyFlow溢出~");
                Position += length;
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// 获取单个字节
        /// </summary>
        /// <returns></returns>
        public byte GetByte()
        {
            try
            {
                if (IsOverflow(1))
                    throw new Exception("ReadOnlyFlow溢出~");

                byte b = 0x00;
                b = _arr[Position];
                Position += 1;
                return b;
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// 获取多个字节
        /// </summary>
        /// <param name="length"></param>
        /// <returns></returns>
        public byte[] GetBytes(int length)
        {
            try
            {
                if (IsOverflow(length))
                    throw new Exception("ReadOnlyFlow溢出~");

                byte[] res = new byte[length];
                int endIndex = Position + length;
                for (int i = Position; i < endIndex; i++)
                    res[i - Position] = _arr[i];
                Position = endIndex;
                return res;
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// 获取多个字节，反向
        /// </summary>
        /// <param name="length"></param>
        /// <returns></returns>
        public byte[] GetReverseBytes(int length)
        {
            try
            {
                if (IsOverflow(length))
                    throw new Exception("ReadOnlyFlow溢出~");

                byte[] res = new byte[length];
                int endIndex = Position + length;
                for (int i = Position; i < endIndex; i++)
                    res[i - Position] = _arr[endIndex - (i - Position + 1)];
                Position = endIndex;
                return res;
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// 根据大端还是小端来获取正向还是反向的字节数组
        /// </summary>
        /// <param name="length"></param>
        /// <returns></returns>
        private byte[] GetBytesWithEndian(int length)
        {
            try
            {
                if (IsBigEndian)
                    return GetReverseBytes(length);
                else
                    return GetBytes(length);
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// 获取2字节无符号整数
        /// </summary>
        /// <returns></returns>
        public ushort GetUShort()
        {
            try
            {
                byte[] b = GetBytesWithEndian(2);
                return BitConverter.ToUInt16(b);
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// 获取2字节有符号整数
        /// </summary>
        /// <returns></returns>
        public short GetShort()
        {
            try
            {
                byte[] b = GetBytesWithEndian(2);
                return BitConverter.ToInt16(b);
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// 获取4字节无符号整数
        /// </summary>
        /// <returns></returns>
        public uint GetUInt()
        {
            try
            {
                byte[] b = GetBytesWithEndian(4);
                return BitConverter.ToUInt32(b);
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// 获取4字节有符号整数
        /// </summary>
        /// <returns></returns>
        public int GetInt()
        {
            try
            {
                byte[] b = GetBytesWithEndian(4);
                return BitConverter.ToInt32(b);
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// 获取8字节无符号整数
        /// </summary>
        /// <returns></returns>
        public ulong GetULong()
        {
            try
            {
                byte[] b = GetBytesWithEndian(8);
                return BitConverter.ToUInt64(b);
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// 获取8字节有符号整数
        /// </summary>
        /// <returns></returns>
        public long GetLong()
        {
            try
            {
                byte[] b = GetBytesWithEndian(8);
                return BitConverter.ToInt64(b);
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// 获取4字节浮点小数
        /// </summary>
        /// <returns></returns>
        public float GetSingle()
        {
            try
            {
                byte[] b = GetBytesWithEndian(4);
                return BitConverter.ToSingle(b);
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// 判断是否溢出
        /// </summary>
        /// <param name="length"></param>
        /// <returns></returns>
        private bool IsOverflow(int length)
        {
            bool res = false;
            try
            {
                if (Position + length > _arr.Length)
                    res = true;
            }
            catch (Exception)
            {
                throw;
            }
            return res;
        }
    }
}
